/*
 * @Author: jingfuu@163.com
 * @Date: 2024-11-12 14:23:48
 * @LastEditTime: 2024-11-27 13:14:43
 * @Description: file content
 */
import { Injectable } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { PrismaService } from 'src/common/prisma/PrismaService';
import { RoleDto } from '../dto/RoleDto';
import RoleQueryParam from '../param/RoleQueryParam';
import PageResult from 'src/common/PageResult';
import { Util } from 'src/common/Util';
import ServiceException from 'src/common/ServiceException';

/*
 * @Author: jingfuu@163.com
 * @Date: 2024-11-12 14:23:48
 * @LastEditTime: 2024-11-25 11:23:43
 * @Description: 角色service
 */
@Injectable()
export class RoleService {
  constructor(private prisma: PrismaService) {}

  async getIdsByUserId(userId: number) {
    const roleIds = await this.prisma.sysUserRole.findMany({
      where: {
        userId: userId,
      },
      select: {
        roleId: true,
      },
    });
    return roleIds.map((item) => item.roleId);
  }

  async getAllRole() {
    let roleList = await this.prisma.sysRole.findMany();
    roleList = roleList.filter((item) => item.roleId !== 1);
    return plainToInstance(RoleDto, roleList);
  }
  async getByUserId(userId: number) {
    const roleIds = await this.prisma.sysUserRole.findMany({
      where: {
        userId: userId,
      },
      select: {
        roleId: true,
      },
    });
    const roleList = await this.prisma.sysRole.findMany({
      where: {
        roleId: {
          in: roleIds.map((item) => item.roleId),
        },
        status: '0',
      },
    });
    return plainToInstance(RoleDto, roleList);
  }

  async updateUserRole(userId: number, roles: number[]) {
    await this.prisma.sysUserRole.deleteMany({
      where: {
        userId: userId,
      },
    });
    await this.prisma.sysUserRole.createMany({
      data: roles.map((item) => ({
        roleId: item,
        userId: userId,
      })),
    });
  }
  async list(param: RoleQueryParam): Promise<PageResult<RoleDto>> {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generateRoleQueryCondition(param);
    const [total, roles] = await this.prisma.$transaction([
      this.prisma.sysRole.count({ where: whereClause }),
      this.prisma.sysRole.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          roleSort: 'asc',
        },
        where: whereClause,
      }),
    ]);
    const rows: RoleDto[] = roles.map((role) => plainToInstance(RoleDto, role));
    return {
      total,
      rows,
    };
  }
  generateRoleQueryCondition(param: RoleQueryParam): any {
    const whereClause: any = {};

    if (param.roleName) {
      whereClause.roleName = {
        contains: param.roleName,
      };
    }

    if (param.roleKey !== undefined) {
      whereClause.roleKey = param.roleKey;
    }

    if (param.status !== undefined) {
      whereClause.status = param.status;
    }

    if (param.params?.beginTime) {
      const beginTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.beginTime}T10:00:00`),
      );
      if (!isNaN(beginTime.getTime())) {
        // Check if the date is valid
        whereClause.createTime = {
          ...whereClause.createTime,
          gte: beginTime,
        };
      }
    }
    if (param.params?.endTime) {
      const endTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.endTime}T23:59:59`),
      );
      if (!isNaN(endTime.getTime())) {
        // Check if the date is valid
        whereClause.createTime = {
          ...whereClause.createTime,
          lte: endTime,
        };
      }
    }
    return whereClause;
  }

  async updateRole(role: RoleDto) {
    if (role.roleId == 1) {
      throw new ServiceException('超级管理员不允许修改');
    }
    await this.prisma.sysRole.update({
      where: { roleId: role.roleId },
      data: {
        roleName: role.roleName,
        roleKey: role.roleKey,
        roleSort: role.roleSort,
        dataScope: role.dataScope,
        menuCheckStrictly: role.menuCheckStrictly,
        deptCheckStrictly: role.deptCheckStrictly,
        status: role.status,
        remark: role.remark,
      },
    });
    if (role.menuIds && role.menuIds.length > 0) {
      // 分配角色菜单
      await this.updateRoleMenu(role.roleId, role.menuIds);
    }
  }
  async updateRoleMenu(roleId: number, menuIds: number[]) {
    //1.删除角色原关联关系
    await this.prisma.sysRoleMenu.deleteMany({
      where: { roleId },
    });
    //2.插入关系
    await this.prisma.sysRoleMenu.createMany({
      data: menuIds.map((menuId) => ({ roleId, menuId })),
    });
  }

  async deleteRole(id: number) {
    if (id == 1) {
      throw new ServiceException('超级管理员不允许删除');
    }
    await this.prisma.sysRole.delete({
      where: { roleId: id },
    });
  }

  async getById(id: number): Promise<RoleDto> {
    const sysRole = this.prisma.sysRole.findUnique({
      where: { roleId: id },
    });
    return plainToInstance(RoleDto, sysRole);
  }

  async addRole(role: RoleDto) {
    // 校验role_key 重复
    await this.checkRoleKey(role.roleKey, null);
    const sysRole = await this.prisma.sysRole.create({
      data: {
        roleName: role.roleName,
        roleKey: role.roleKey,
        roleSort: role.roleSort,
        dataScope: role.dataScope,
        menuCheckStrictly: role.menuCheckStrictly,
        deptCheckStrictly: role.deptCheckStrictly,
        status: role.status,
        remark: role.remark,
      },
    });
    if (role.menuIds && role.menuIds.length > 0) {
      // 分配角色菜单
      await this.updateRoleMenu(sysRole.roleId, role.menuIds);
    }
  }
  async checkRoleKey(roleKey: string, roleId: number) {
    const role = await this.prisma.sysRole.findFirst({
      where: { roleKey: roleKey },
    });
    if (!roleId) {
      if (role) {
        throw new ServiceException('角色权限字符' + roleKey + '已存在');
      }
    } else {
      if (role && role.roleId != roleId) {
        throw new ServiceException('角色权限字符' + roleKey + '已存在');
      }
    }
  }

  async exportRole(param: RoleQueryParam) {
    const whereClause: any = this.generateRoleQueryCondition(param);
    const sysRoles = await this.prisma.sysRole.findMany({
      orderBy: {
        createTime: 'desc',
      },
      where: whereClause,
    });
    const roleDtos = plainToInstance(RoleDto, sysRoles);
    // 设置列头
    const header = [
      { header: '角色序号', key: 'id', width: 10 },
      { header: '角色名称', key: 'roleName', width: 20 },
      { header: '角色权限', key: 'roleKey', width: 20 },
      { header: '角色排序', key: 'roleSort', width: 20 },
      { header: '角色状态', key: 'status', width: 20 },
    ];
    const roles = roleDtos.map((role) => {
      return {
        id: role.roleId,
        roleName: role.roleName,
        roleKey: role.roleKey,
        roleSort: role.roleSort,
        status: role.status == '0' ? '正常' : '停用',
      };
    });
    return Util.excelExport(roles, header);
  }
}
